#include "primitive.h"

#include "collision.h"

#include <QDebug>

#define PI 3.1415926535897
#define DEG_TO_RAD(angle) angle*57,295779513084

#include "glm/gtc/matrix_transform.hpp"

Primitive::Primitive(PrimitiveType type)
 : type(type)
   //update_matrix(true),
   //scaleFactors(1.0f, 1.0f, 1.0f, 0.0f)
{
}


Box::Box(const glm::vec4 &origin, float side)
    :Primitive(BoxPrimitive),
      m_origin(origin),
      m_side(side)
{
    m_frame = QSharedPointer<Frame>(new Frame);
    float half_side = side/2;
    glm::vec4 first = origin - glm::vec4 (half_side, half_side, half_side, 0.0);
    glm::vec4 temp;

    m_points[0] = m_points[1]  = m_points[2]  = m_points[3]  = m_points[4]  = m_points[5]  = m_points[6]  = m_points[7] = first;

    temp.x = side; temp.y = 0; temp.z = 0;
    m_points[1] = m_points[1] + temp;
    temp.x = side; temp.y = side; temp.z = 0;
    m_points[2] = m_points[2] + temp;
    temp.x = 0; temp.y = side; temp.z = 0;
    m_points[3] = m_points[3] + temp;

    temp.x = 0; temp.y = 0; temp.z = side;
    m_points[4] = m_points[4] + temp;
    temp.x = side; temp.y = 0; temp.z = side;
    m_points[5] = m_points[5] + temp;
    temp.x = side; temp.y = side; temp.z = side;
    m_points[6] = m_points[6] + temp;
    temp.x = 0; temp.y = side; temp.z = side;
    m_points[7] = m_points[7] + temp;
}

CollisionState Box::doCollide(Primitive &primitive)
{
    CollisionState ret_state;
    Primitive *temp_primitive = reinterpret_cast<Primitive*>(&primitive);

    switch(primitive.type) {
    case BoxPrimitive:
    {
        //qDebug() << "OBB-OBB Collision";
        Box *temp = reinterpret_cast<Box*>(temp_primitive);
        ret_state = obb_obb_collision(*temp, *this);
        break;
    }
    case SpherePrimitive:
    {
        //qDebug() << "Box-Sphere Collision";
        Sphere *temp = reinterpret_cast<Sphere*>(temp_primitive);
        ret_state = sphere_cube_collision(*temp, *this);
        break;
    }
    default:
        break;
    }
    return ret_state;
}

// This verification only works for axis-aligned cubes
bool Box::inside(const glm::vec4 &pt)
{
    // TODO: implement this taking int occount the box transformations
    // First, verifies if the point is within (x,y) square
    if ( (pt.x >= m_points[0].x && pt.x <= m_points[1].x) &&
         (pt.y >= m_points[0].y && pt.y <= m_points[3].y) ) {
        if (pt.z >= m_points[0].z && pt.z <= m_points[4].z) {
            return true;
        }
    }
    return false;
}

Sphere::Sphere(const glm::vec4 &origin, float radius)
    :Primitive(SpherePrimitive),
      m_origin(origin),
      m_radius(radius)
{
    m_frame = QSharedPointer<Frame>(new Frame);
//    scale(2, 0.5, 1.0);
//    rotateX(45);                                          FOR TESTING PURPOSES
//    translate(0.0, 1, 0.0);
}

CollisionState Sphere::doCollide(Primitive &primitive)
{
    switch(primitive.type) {
    case BoxPrimitive:
        break;
    case SpherePrimitive:
        break;
    default:
        break;
    }
}

bool Sphere::inside(const glm::vec4 &pt)
{
    float val = (pt.x - m_origin.x)*(pt.x - m_origin.x) +
                (pt.y - m_origin.y)*(pt.y - m_origin.y) +
                (pt.z - m_origin.z)*(pt.z - m_origin.z) -
                m_radius*m_radius;
    return (val <= 0.0f);
}

//void Primitive::scale(float x, float y, float z)
//{
//    scaleFactors.x = x;
//    scaleFactors.y = y;
//    scaleFactors.z = z;
//}

//void Primitive::scale(glm::vec4 factors)
//{
//    scaleFactors = factors;
//}
